#ifndef NE_STL_INCLUDENE_STL_ANY_H
#define NE_STL_INCLUDENE_STL_ANY_H
#pragma warning(disable : 4503)

#include "ne_stl_build.h"

namespace nstd {

struct type_id_t {
    const char* name;
    type_id_t(const char* _name)
        : name(_name) {}
    type_id_t(const type_id_t& other)
        : name(other.name) {}
    bool operator<(const type_id_t& other) const { return name < other.name; }
    bool operator==(const type_id_t& other) const { return (name == other.name || strcmp(name, other.name) == 0); }
    bool operator!=(const type_id_t& other) const { return !operator==(other); }
};

class any {
public:
    template <typename T>
    struct type_id_for_t {
        static type_id_t id() { return type_id_t{typeid(T).name()}; };
    };
#define TypeIDForT(TClass) nstd::any::type_id_for_t<typename std::decay<TClass>::type>::id()
public:  // structors
    any()
        : content(0) {}

    template <typename _ValueType>
    any(const _ValueType& value)
        : content(new holder<_ValueType>(value)) {}

    any(const any& other)
        : content(other.content ? other.content->clone() : 0) {}

    ~any() { delete content; }

public:
    template <typename _Ty>
    static const type_id_t type_id() {
        return TypeIDForT(_Ty);
    }

public:  // modifiers
    any& swap(any& rhs) {
        placeholder* _temp = content;
        content = rhs.content;
        rhs.content = _temp;
        return *this;
    }

    template <typename _ValueType>
    any& operator=(const _ValueType& rhs) {
        any(rhs).swap(*this);
        return *this;
    }

    any& operator=(any rhs) {
        rhs.swap(*this);
        return *this;
    }

public:  // queries
    bool empty() const { return !content; }

private:  // types
    class placeholder {
    public:  // structors
        placeholder(const type_id_t index)
            : type_id_index_(index) {}
        virtual ~placeholder() {}

    public:  // queries
        virtual placeholder* clone() const = 0;

        type_id_t type_id_index_;
    };

    template <typename _ValueType>
    class holder : public placeholder {
    public:  // structors
        holder(const _ValueType& value)
            : placeholder(TypeIDForT(_ValueType))
            , held(value) {}

    public:  // queries
        virtual placeholder* clone() const { return new holder(held); }

    public:  // representation
        _ValueType held;

    private:  // intentionally left unimplemented
        holder& operator=(const holder&);
    };

private:  // representation
    template <typename _ValueType>
    friend _ValueType* any_cast(any*);

    template <typename _ValueType>
    friend _ValueType* UnsafeanyCast(any*);

    placeholder* content;
};

class bad_any_cast {
public:
    const char* what() const throw() {
        return "bad_any_cast: "
               "failed conversion any_cast";
    }
};

template <typename _ValueType>
_ValueType* any_cast(any* operand) {
    _ValueType* ret = nullptr;
    do {
        if (operand == nullptr)
            break;
        if (TypeIDForT(_ValueType).name != operand->content->type_id_index_.name)
            break;
        ret = &static_cast<any::holder<_ValueType>*>(operand->content)->held;
    } while (false);

    return ret;
}

template <typename _ValueType>
inline const _ValueType* any_cast(const any* operand) {
    return any_cast<_ValueType>(const_cast<any*>(operand));
}

template <typename _ValueType>
_ValueType any_cast(any& operand) {
    typedef typename std::decay<_ValueType>::type nonref;
    static_assert(!(std::is_reference<nonref>::value), "still right reference");
    nonref* result = any_cast<nonref>(&operand);
    return *result;
}
template <typename _ValueType>
inline _ValueType any_cast(const any& operand) {
    typedef typename std::decay<_ValueType>::type nonref;
    static_assert(!std::is_reference<nonref>::value, "still right reference");
    return any_cast<const nonref&>(const_cast<any&>(operand));
}
template <typename _ValueType>
inline _ValueType* UnsafeanyCast(any* operand) {
    return &static_cast<any::holder<_ValueType>*>(operand->content)->held;
}

template <typename _ValueType>
inline const _ValueType* UnsafeanyCast(const any* operand) {
    return UnsafeanyCast<_ValueType>(const_cast<any*>(operand));
}

}  // namespace nstd

#endif  // !NE_STL_INCLUDENE_STL_ANY_H
